<?php

namespace app\common;

use GuzzleHttp\Client;
use GuzzleHttp\Exception\RequestException;
use Psr\Http\Client\ClientExceptionInterface;
use app\admin\model\SystemOpenRequestLog;
use think\facade\Log;

class ApiClient
{
    private $client;
    private $baseUri;
    private $logFullResponse = false; // 新增：是否记录完整响应的标记

    public function __construct(string $baseUri, $defaultTimeout = 300, $defaultConnectTimeout = 30)
    {
        $this->client = new Client([
            'verify' => false,
            'headers' => [
                'Content-Type' => 'application/json'
            ],
            'timeout' => $defaultTimeout,
            'connect_timeout' => $defaultConnectTimeout
        ]);
        $this->baseUri = rtrim($baseUri, '/'); // 去除末尾斜杠
    }

    /**
     * 设置是否记录完整响应
     */
    public function setLogFullResponse(bool $value)
    {
        $this->logFullResponse = $value;
        return $this;
    }


    public function overallGet(string $endpoint, array $options = [])
    {
        return $this->sendOverallRequest('GET', $endpoint, $options);
    }

    public function overallPost(string $endpoint, array $options = [])
    {
        return $this->sendOverallRequest('POST', $endpoint, $options);
    }

    public function overallPut(string $endpoint, array $options = [])
    {
        return $this->sendOverallRequest('PUT', $endpoint, $options);
    }

    public function overallDelete(string $endpoint, array $options = [])
    {
        return $this->sendOverallRequest('DELETE', $endpoint, $options);
    }

    public function overallPatch(string $endpoint, array $options = [])
    {
        return $this->sendOverallRequest('PATCH', $endpoint, $options);
    }

    /**
     * 新增：返回完整响应的方法
     */
    private function sendOverallRequest(string $method, string $endpoint, array $options)
    {
        ini_set('memory_limit', '1024M');  // 设置为 256MB
        try {
            $response = $this->client->request($method, $this->baseUri . '/' . ltrim($endpoint, '/'), $options);

            // 记录请求日志
            $this->logRequest($method, $endpoint, $options, $response);

            return [
                'status' => $response->getStatusCode(),
                'headers' => $response->getHeaders(),
                'body' => json_decode((string)$response->getBody(), true),
                'response' => $response
            ];
        } catch (RequestException $e) {

            if ($e->hasResponse()) {
                $response = $e->getResponse();
                $this->logRequest($method, $endpoint, $options, $response);
                return [
                    'status' => $response->getStatusCode(),
                    'headers' => $response->getHeaders(),
                    'body' => json_decode((string)$response->getBody(), true),
                    'response' => $response
                ];
            }
            throw $e;
        } catch (ClientExceptionInterface $e) {

            $logData = [
                'message' => $e->getMessage(),
                'file' => $e->getFile(),
                'line' => $e->getLine(),
                'request' => [
                    'path' => $endpoint,
                    'method' => $method,
                    'options' => $options
                ]
            ];

            Log::error('API请求异常：' . json_encode($logData, JSON_UNESCAPED_UNICODE));
            throw $e;
        }
    }


    /**
     * 发送 GET 请求.
     *
     * @param string $endpoint 相对于 $baseUri 的路径
     * @param array $options Guzzle 请求选项
     * @return mixed
     */
    public function get(string $endpoint, array $options = [])
    {
        return $this->sendRequest('GET', $endpoint, $options);
    }

    /**
     * 发送 POST 请求.
     *
     * @param string $endpoint 相对于 $baseUri 的路径
     * @param array $options Guzzle 请求选项
     * @return mixed
     */
    public function post(string $endpoint, array $options = [])
    {
        return $this->sendRequest('POST', $endpoint, $options);
    }

    /**
     * 发送 PUT 请求.
     *
     * @param string $endpoint 相对于 $baseUri 的路径
     * @param array $options Guzzle 请求选项
     * @return mixed
     */
    public function put(string $endpoint, array $options = [])
    {
        return $this->sendRequest('PUT', $endpoint, $options);
    }

    /**
     * 发送 DELETE 请求.
     *
     * @param string $endpoint 相对于 $baseUri 的路径
     * @param array $options Guzzle 请求选项
     * @return mixed
     */
    public function delete(string $endpoint, array $options = [])
    {
        return $this->sendRequest('DELETE', $endpoint, $options);
    }

    /**
     * 发送 HTTP 请求.
     *
     * @param string $method 请求方法
     * @param string $endpoint 相对于 $baseUri 的路径
     * @param array $options Guzzle 请求选项
     * @return mixed
     */
    private function sendRequest(string $method, string $endpoint, array $options)
    {
        try {
            $response = $this->client->request($method, $this->baseUri . '/' . ltrim($endpoint, '/'), $options);
            $this->logRequest($method, $endpoint, $options, $response); // 记录请求日志
            return json_decode((string)$response->getBody(), true); // 假设返回 JSON 数据
        } catch (RequestException $e) {
            if ($e->hasResponse()) {
                $this->logRequest($method, $endpoint, $options, $e->getResponse());
                return json_decode((string)$e->getResponse()->getBody(), true);
            }
            throw $e; // 或者处理异常情况
        } catch (ClientExceptionInterface $e) {
            // 处理客户端错误
            throw $e;
        }
    }

    /**
     * 抽取日志记录逻辑
     */
    private function logRequest(string $method, string $endpoint, array $options, $response)
    {
        // 获取请求参数，检查所有可能的参数类型
        $requestParams = $options['json'] ?? $options['form_params'] ?? $options['query'] ?? [];

        $requestData = [
            'request_url' => $this->baseUri . '/' . ltrim($endpoint, '/'),
            'request_params' => !empty($requestParams) ? json_encode($requestParams, JSON_UNESCAPED_UNICODE) : '',
            'request_method' => $method,
            'request_headers' => isset($options['headers']) ? json_encode($options['headers'], JSON_UNESCAPED_UNICODE) : '',
            'request_body' => isset($options['body']) ? json_encode($options['body'], JSON_UNESCAPED_UNICODE) : '',
            'request_timestamp' => date('Y-m-d H:i:s'),
            'response_code' => $response->getStatusCode(),
            'response_body' => $this->logFullResponse ?
                json_encode([
                    'status' => $response->getStatusCode(),
                    'headers' => $response->getHeaders(),
                    'body' => (string)$response->getBody()
                ], JSON_UNESCAPED_UNICODE) :
                substr((string)$response->getBody(), 0, 65535),
            'type' => 1,
            'create_time' => date('Y-m-d H:i:s')
        ];
        SystemOpenRequestLog::create($requestData);
    }
}
